package br.com.primeira.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.Hashtable;

import javax.xml.parsers.DocumentBuilderFactory;

import org.andengine.audio.music.Music;
import org.andengine.audio.music.MusicFactory;
import org.andengine.audio.sound.Sound;
import org.andengine.audio.sound.SoundFactory;
import org.andengine.engine.Engine;
//import org.andengine.opengl.font.Font;
import org.andengine.opengl.texture.TextureOptions;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.andengine.opengl.texture.region.TextureRegion;
import org.andengine.opengl.texture.region.TiledTextureRegion;
import org.andengine.util.debug.Debug;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import br.com.primeira.entities.Map;
import br.com.primeira.entities.Tile;

import android.content.Context;
//import android.graphics.Typeface;
import android.content.res.AssetManager;
import android.util.SparseArray;

public class AssetPool
{
	private static AssetPool instance;
	
	private Context context;
	private Engine mEngine;
	
	private Hashtable<String, TextureRegion> images;
	private Hashtable<String, TiledTextureRegion> tiles;
	private Hashtable<String, Map> maps;
	private Hashtable<String, Sound> sounds;
	private Hashtable<String, Music> musics;
	//private Hashtable<String, Font> fonts;
	
	private AssetPool()
	{
		
	}
	
	public static AssetPool getInstance()
	{
		if(instance == null)
			instance = new AssetPool();
		
		return instance;
	}
	
	public void init(Context context, Engine engine)
	{
		this.context = context;
		this.mEngine = engine;
	}
	
	//
	// Image
	//
	
	public void loadTextureRegion(String key, String path, int width, int height)
	{
		if (images == null)
			images = new Hashtable<String, TextureRegion>();
		
		BitmapTextureAtlas textureAtlas = new BitmapTextureAtlas(mEngine.getTextureManager(), width, height, TextureOptions.NEAREST);
		TextureRegion region = BitmapTextureAtlasTextureRegionFactory.createFromAsset(textureAtlas, context, path, 0, 0);
		textureAtlas.load();
		
		images.put(key, region);
	}
	
	public TextureRegion getTextureRegion(String key)
	{
		return images.get(key);
	}
	
	//
	// Animated Image
	//
	
	public void loadTiledTextureRegion(String key, String path, int width, int height, int columns, int rows)
	{
		if (tiles == null)
			tiles = new Hashtable<String, TiledTextureRegion>();
		
		BitmapTextureAtlas textureAtlas = new BitmapTextureAtlas(mEngine.getTextureManager(), width, height, TextureOptions.NEAREST);
		TiledTextureRegion region = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(textureAtlas, context, path, 0, 0, columns, rows);
		textureAtlas.load();
		
		tiles.put(key, region);
	}
	
	public TiledTextureRegion getTiledTextureRegion(String key)
	{
		return tiles.get(key);
	}
	
	public void loadMap(String key, String path)
	{
		if (maps == null)
			maps = new Hashtable<String, Map>();
		
		AssetManager am = context.getAssets();
		Map map = null;
		
		try
		{	
			InputStream is = am.open("maps/" + path);
			
			map = parse(is);
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		
		maps.put(key, map);
	}
	
	public Map getMap(String key)
	{
		return maps.get(key);
	}
	
	//
	// Sound
	//
	
	public void loadSound(String key, String path)
	{
		if (sounds == null)
			sounds = new Hashtable<String, Sound>();
		
		try 
		{
			Sound sound = SoundFactory.createSoundFromAsset(mEngine.getSoundManager(), context, path);
			sounds.put(key, sound);
		}
		catch (IOException e)
		{
			Debug.e(e);
		}
	}
	
	public Sound getSound(String key)
	{
		return sounds.get(key);
	}
	
	//
	// Music
	//
	
	public void loadMusic(String key, String path)
	{
		if (musics == null)
			musics = new Hashtable<String, Music>();
		
		try
		{
			Music music = MusicFactory.createMusicFromAsset(mEngine.getMusicManager(), context, path);
			musics.put(key, music);
		}
		catch (IOException e)
		{
			Debug.e(e);
		}
	}
	
	public Music getMusic(String key)
	{
		return musics.get(key);
	}
	
	//
	// Font
	// 

	/*public void loadFont(String key, Typeface typeface, float size, boolean antiAlias, int color)
	{
		if (fonts == null)
			fonts = new Hashtable<String, Font>();
		
		Texture texture = new Texture(256, 256, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		Font font = new Font(texture, typeface, size, antiAlias, color);
		engine.getTextureManager().loadTexture(texture);
		engine.getFontManager().loadFont(font);
		fonts.put(key, font);
	}
	
	public Font getFont(String key)
	{
		return fonts.get(key);
	}*/
	
	// TODO
	/*
	 * Pegar tamanho de cada tileset do XML
	 * Pegar tamanho do mapa em Tiles do XML e preencher em Mapa
	 * */
	private Map parse(InputStream file)
	{
		SparseArray<Tile> tiles = new SparseArray<Tile>();
		int mapWidth = 0;
		int mapHeight = 0;
		
		try 
		{
			// Parsing document
			Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(file);
			doc.getDocumentElement().normalize();
			
			// Reading <level> and retrieving map width and heigth
			Element level = ((Element)doc.getElementsByTagName("level").item(0));
			mapWidth = Integer.parseInt(level.getAttribute("width"));
			mapHeight = Integer.parseInt(level.getAttribute("height"));
			
			// Reading <floor> and retrieving tileset file name
			String tilesetImage = ((Element)doc.getElementsByTagName("floor").item(0)).getAttribute("tileset");
			
			// Loading tileset to use on the creation of tiles
			loadTiledTextureRegion("floor", "tilesets/" + tilesetImage + ".png", 128, 128, 8, 8);
			TiledTextureRegion tileset = getTiledTextureRegion("floor");
			
			// Reading <tile> tags
			NodeList nodeList = doc.getElementsByTagName("tile");
			
			for (int i = 0; i < nodeList.getLength(); i++)
			{
				Node node = nodeList.item(i);
				Element element = (Element)node;
				
				int index = (Integer.parseInt(element.getAttribute("ty")) * 8) + Integer.parseInt(element.getAttribute("tx"));
				
				tiles.put(i, new Tile(mEngine.getVertexBufferObjectManager(),
									  tileset.getTextureRegion(index),
									  Integer.parseInt(element.getAttribute("x")) * 16,
									  Integer.parseInt(element.getAttribute("y")) * 16));
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		
		return new Map(tiles, mapWidth, mapHeight);
	}
}